<template>
  <view>
    <wd-popup
      position="bottom"
      :hide-when-close="true"
      :lock-scroll="true"
      v-model="showPopup"
      :modal="mask"
      :close-on-click-modal="maskClosable"
      :modal-style="maskStyle"
      :duration="duration"
      :safe-area-inset-bottom="safeAreaInsetBottom"
      :lazy-render="lazyRender"
      :z-index="zIndex"
      :custom-class="popupCustomClass"
      :custom-style="popupCustomStyle"
      @close="handleclose"
      @click-modal="handleClickMask"
      @before-enter="handleEnter('before-enter')"
      @enter="handleEnter('enter')"
      @after-enter="handleEnter('after-enter')"
      @before-leave="handleLeave('before-leave')"
      @leave="handleLeave('leave')"
      @after-leave="handleLeave('after-leave')"
    >
      <wd-floating-panel
        :custom-class="customClass"
        :custom-style="getFloatingPanelStyle"
        v-model:height="height"
        :anchors="getAnchors"
        :duration="duration"
        :content-draggable="contentDraggable"
        :safe-area-inset-bottom="safeAreaInsetBottom"
        :show-scrollbar="showScrollbar"
        @heightChange="handleHeightChange"
      >
        <slot />
      </wd-floating-panel>
    </wd-popup>
  </view>
</template>

<script lang="ts" setup>
  import { type CSSProperties, ref, watch } from 'vue';
  import { addUnit } from 'wot-design-uni/components/common/util';

  import { styleToString } from '@/utils';
  import { isArray, isNumber, isString } from '@/utils/is';

  import { floatingPanelProps } from './props';

  defineOptions({
    name: 'ea-floating-panel',
    options: {
      virtualHost: true,
      addGlobalClass: true,
      styleIsolation: 'shared',
    },
  });
  const props = defineProps(floatingPanelProps);
  const emit = defineEmits([
    'update:modelValue', // 是否显示改变时出发
    'close', // 弹出层关闭时触发
    'click-mask', // 点击遮罩时触发
    'before-enter', // 进入前触发
    'enter', // 进入时触发
    'after-enter', // 进入后触发
    'before-leave', // 离开前触发
    'leave', // 离开时触发
    'after-leave', // 离开后触发
    'height-change', // 面板显示高度改变且结束拖动后触发
  ]);

  /** 当前面板的显示高度 */
  const height = defineModel<number>('height', { default: 0 });

  /** 显示弹层 */
  const showPopup = ref<boolean>(false);

  const { statusBarHeight, windowHeight } = uni.getSystemInfoSync();

  /** 获取自定义锚点 */
  const getAnchors = computed(() => {
    const { anchors, slideClosable } = props;
    let _anchors: number[] | undefined;
    if (isArray(anchors)) {
      _anchors = anchors.map((m) => {
        if (isNumber(m)) {
          m = Math.abs(m);
          if (m > 1) {
            return m;
          } else {
            return Math.round(m * windowHeight);
          }
        } else if (isString(m)) {
          if (m.endsWith('%')) {
            return Math.round((parseFloat(m) / 100) * windowHeight);
          } else {
            return Number(m.match(/\d+/g).join(''));
          }
        }
        return 0;
      });
    }
    if (slideClosable && _anchors?.length > 0 && !_anchors?.includes(0)) {
      _anchors.push(0);
    }
    return _anchors?.sort((a, b) => a - b);
  });

  watch(
    () => props.modelValue,
    (newValue) => {
      showPopup.value = newValue;
      if (showPopup.value && height.value <= 0) {
        height.value = getAnchors.value?.filter((f) => f > 0)?.sort((a, b) => a - b)?.[0] || 0;
      }
    },
    { deep: true, immediate: true },
  );

  /** 处理关闭 */
  function handleclose() {
    emit('update:modelValue', false);
    emit('close');
  }
  /** 处理遮罩点击 */
  function handleClickMask() {
    emit('click-mask');
  }
  /** 处理进入 */
  function handleEnter(event: 'before-enter' | 'enter' | 'after-enter') {
    emit(event);
  }
  /** 处理离开 */
  function handleLeave(event: 'before-leave' | 'leave' | 'after-leave') {
    emit(event);
  }

  /** 面板显示高度改变且结束拖动后触发 */
  const handleHeightChange = ({ height }: { height: number }) => {
    emit('height-change', { height });
    const { slideClosable } = props;
    if (slideClosable && height === 0) {
      showPopup.value = false;
      handleclose();
    }
  };

  /** 获取浮动面板样式 */
  const getFloatingPanelStyle = computed(() => {
    const style: CSSProperties = {};
    const { customStyle } = props;
    if (height.value === windowHeight) {
      const barHeight = statusBarHeight > 0 ? addUnit((statusBarHeight || 0) + 0) : '0px';
      style['border-top-left-radius'] = '0px';
      style['border-top-right-radius'] = '0px';
      style.height = `calc(100% - ${barHeight})`;
      style['padding-top'] = barHeight;
    }
    let styleString = styleToString(style);
    if (customStyle) {
      styleString = `${styleString}${customStyle}`;
    }
    return styleString;
  });
</script>

<style lang="scss" scoped>
  @import './index';
</style>
